﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using DCS.AdministrationClient.DCS_Service;


namespace DCS.AdministrationClient.Forms
{
    public partial class TaskManagerForm : Form
    {
        /// <summary> Список активных задач. </summary>
        private readonly List<TaskInfo> activeTasks = new List<TaskInfo>();

        /// <summary> Список сформированных, но ещё не отправленных на сервер задач. </summary>
        private readonly List<TaskPack> formedTasks = new List<TaskPack>();

        private Guid selectedActiveTask;

        public TaskManagerForm()
        {
            InitializeComponent();
        }

        private void SendTaskButtonClick(object sender, EventArgs e)
        {
            if (listViewFormedTasks.SelectedItems.Count > 0)
            {
                var sendingTask = GetTaskFromList(new Guid(listViewFormedTasks.SelectedItems[0].Name));

                if (sendingTask.TaskName == null)
                {
                    MessageBox.Show("Задание повреждено.", "Ошибка получения задания", MessageBoxButtons.OK,
                                    MessageBoxIcon.Error);
                    return;
                }
                try
                {
                    AddLogMessage(Program.Context.DcsService.AddTask(sendingTask), LogMessageType.WebMessage);
                }
                catch (Exception exc)
                {
                    MessageBox.Show(exc.Message);
                }
            }
            else
            {
                labelHint.Text = "Задание для отправки не выбрано.";
            }
            Program.Context.DcsService.GetAllTaskInfos(Program.Context.Id);
        }

        private void ExitToolStripMenuItemClick(object sender, EventArgs e)
        {
            AddLogMessage("Завершение работы клиента.", LogMessageType.Info);

            Close();
        }

        private TaskPack GetTaskFromList(Guid taskGuid)
        {
            return formedTasks.FirstOrDefault(t => t.Guid == taskGuid);
        }

        private void DeleteTaskFromList(Guid taskGuid)
        {
            for (int i = 0; i < formedTasks.Count; i++)
            {
                if (formedTasks[i].Guid != taskGuid) continue;

                formedTasks.Remove(formedTasks[i]);

                return;
            }
        }

        private TaskInfo GetTaskInfoFromList(Guid taskGuid)
        {
            return activeTasks.FirstOrDefault(t => t.Id == taskGuid);
        }

        private void OnRefreshActiveTasks(object sender, GetAllTaskStatesCompletedEventArgs eventArgs)
        {
            RefreshActiveTasks(eventArgs.Result);
        }

        private void RefreshActiveTasks(IEnumerable<TaskInfo> infos)
        {
            try
            {
                listViewActiveTasks.Items.Clear();
                activeTasks.Clear();

                foreach (var t in infos)
                {
                    listViewActiveTasks.Items.Add(t.Id.ToString(), t.Name, t.State + ".png");
                    activeTasks.Add(t);
                }

                RefreshTaskInfo(selectedActiveTask);
                Program.Context.DcsService.GetAllTaskStatesAsync(Program.Context.Id, true);
            }
            catch
            {
            }
        }

        private void RefreshFormedTasks()
        {
            listViewFormedTasks.Items.Clear();

            foreach (TaskPack t in formedTasks)
            {
                listViewFormedTasks.Items.Add(t.Guid.ToString(), t.TaskName, "WorldTask.png");
            }
        }

        private void ListViewActiveTasksItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            selectedActiveTask = new Guid(e.Item.Name);
            RefreshTaskInfo(selectedActiveTask);
            ShowAvailableOperations();
            buttonDeleteTask.Enabled = false;
        }

        private void RefreshTaskInfo(Guid taskId)
        {
            try
            {
                var task = GetTaskInfoFromList(taskId);

                textBoxTaskName.Text = task.Name;
                textBoxTaskDeadline.Text = task.Deadline.ToString();
                textBoxTaskPriority.Text = task.Priority;
                progressBarPercentCompleted.Value = Convert.ToInt32(task.Progress);
                
                var percentage = Convert.ToInt32(task.Progress);
                labelPercentCompleted.Text = percentage.ToString("N1") + "%";
            }
            catch (Exception)
            {
            }
        }

        private void RefreshTaskPackInfo(Guid taskId)
        {
            try
            {
                TaskPack task = GetTaskFromList(taskId);

                textBoxTaskName.Text = task.TaskName;
                textBoxTaskPortionsNumber.Text = task.PortionsNumber.ToString();
                textBoxTaskDeadline.Text = task.Deadline.ToString();
                textBoxTaskPriority.Text = Utility.Utility.Priorities[task.Priority];
                textBoxTaskDependenciesNumber.Text = task.Dependencies.Length.ToString();
            }
            catch (Exception)
            {
            }
        }

        private void AddLogMessage(string log, LogMessageType type)
        {
            Program.Context.Log.Add(new LogRecord {Message = log, Time = DateTime.Now, Type = type});

            if (type == LogMessageType.Info)
            {
                labelHint.Text = log;
            }
        }

        private void TaskManagerFormLoad(object sender, EventArgs e)
        {
            AddLogMessage("Запуск клиента.", LogMessageType.Info);

            Program.Context.DcsService.GetAllTaskStatesCompleted += OnRefreshActiveTasks;
            Program.Context.DcsService.GetAllTaskStatesAsync(Program.Context.Id, false);
        }

        private void TaskManagerFormFormClosing(object sender, FormClosingEventArgs e)
        {
            Program.Context.DcsService.GetAllTaskStatesCompleted -= OnRefreshActiveTasks;
            Program.Greetings.Show();
        }

        private void ListViewFormedTasksItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            RefreshTaskPackInfo(new Guid(e.Item.Name));
            buttonDeleteTask.Enabled = true;
        }

        

        private void ButtonAddNewTaskClick(object sender, EventArgs e)
        {
            var addTaskForm = new TaskPreparationForm();

            if (addTaskForm.ShowDialog() != DialogResult.OK) return;

            TaskPack formedTask = addTaskForm.Task;
            listViewFormedTasks.Items.Add(formedTask.Guid.ToString(), formedTask.TaskName, "Add.png");
            formedTasks.Add(formedTask);
        }

        private void ButtonDeleteTaskClick(object sender, EventArgs e)
        {
            if (listViewFormedTasks.SelectedItems.Count > 0)
            {
                DeleteTaskFromList(new Guid(listViewFormedTasks.SelectedItems[0].Name));
                RefreshFormedTasks();
            }
        }

        private void BigIconsToolStripMenuItemClick(object sender, EventArgs e)
        {
            listViewActiveTasks.View = View.LargeIcon;
            listViewFormedTasks.View = View.LargeIcon;
        }

        private void SmallIconsToolStripMenuItemClick(object sender, EventArgs e)
        {
            listViewActiveTasks.View = View.SmallIcon;
            listViewFormedTasks.View = View.SmallIcon;
        }

        private void ListToolStripMenuItemClick(object sender, EventArgs e)
        {
            listViewActiveTasks.View = View.List;
            listViewFormedTasks.View = View.List;
        }

        private void HeadersToolStripMenuItemClick(object sender, EventArgs e)
        {
            listViewActiveTasks.View = View.Tile;
            listViewFormedTasks.View = View.Tile;
        }

        private void DeleteAllTasksFromServerClick(object sender, EventArgs e)
        {
            if (
                MessageBox.Show("ВНИМАНИЕ! Все данные будут удаленны из базы данных!\n\nПродолжить?", "Внимание",
                                MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) ==
                DialogResult.Yes)
            {
                AddLogMessage("Сервер перезапущен", LogMessageType.Warning);
                AddLogMessage(string.Format("Удалено записей: {0}", Program.Context.DcsService.RestartService()),
                              LogMessageType.WebMessage);
            }
        }

        #region Menus

        private void AddTaskToolStripMenuItemClick(object sender, EventArgs e)
        {
            var addTaskForm = new TaskPreparationForm();

            if (addTaskForm.ShowDialog() != DialogResult.OK) return;
            TaskPack formedTask = addTaskForm.Task;
            listViewFormedTasks.Items.Add(formedTask.Guid.ToString(), formedTask.TaskName, "Add.png");
            formedTasks.Add(formedTask);
        }

        private void DeleteTaskToolStripMenuItemClick(object sender, EventArgs e)
        {
            if (listViewFormedTasks.SelectedItems.Count <= 0) return;

            DeleteTaskFromList(new Guid(listViewFormedTasks.SelectedItems[0].Name));
            RefreshFormedTasks();
        }

        #endregion

        private void toolStripButtonLog_Click(object sender, EventArgs e)
        {
            var logBrowser = new LogBrowser();
            logBrowser.Show();
        }

        private void ShowAvailableOperations()
        {
            var info = GetTaskInfoFromList(selectedActiveTask);

            // Если задание выполнено его можно загрузить
            var isComplete = Convert.ToInt32(info.Progress) == 100;
            var isTaskResultDownloaded = Directory.Exists(info.Id.ToString());
            
            downloadResult.Enabled = isComplete;
            downloadResultToolStrip.Enabled = isComplete;
            downloadResultToolStripMain.Enabled = isComplete;

            // Если оно уже загружено, то его можно показать в папке, запустить приложение или удалить            
            browseResult.Enabled = isTaskResultDownloaded;
            browseResultToolStrip.Enabled = isTaskResultDownloaded;
            
            runApplication.Enabled = isTaskResultDownloaded;
            runApplicationToolStrip.Enabled = isTaskResultDownloaded;

            deleteResult.Enabled = isTaskResultDownloaded;
            deleteResultToolStrip.Enabled = isTaskResultDownloaded;

            ShowAvailableContextMenuOperations(isComplete, isTaskResultDownloaded);
        }

        private void ShowAvailableContextMenuOperations(bool isComplete, bool taskResultDownloaded)
        {
            download.Enabled = isComplete;
            browse.Enabled = taskResultDownloaded;
            delete.Enabled = taskResultDownloaded;
            run.Enabled = taskResultDownloaded;
        }

        private void DownloadResultClick(object sender, EventArgs e)
        {
            try
            {
                var result = Program.Context.DcsService.GetResult(selectedActiveTask);
                textBoxExpendedTime.Text = (result.CompleteDate - result.CreationDate).ToString();

                if (result.TaskGuid != Guid.Empty)
                {
                    Directory.CreateDirectory(result.TaskGuid.ToString());

                    for (var i = 0; i < result.PartialResults.Length; i++)
                    {
                        foreach (var file in result.PartialResults[i].ResultFiles)
                        {
                            Directory.CreateDirectory(result.TaskGuid + "\\Portion_" + i);
                            File.WriteAllBytes(
                                result.TaskGuid + "\\Portion_" + i + "\\" +
                                file.FileName.Substring(
                                    file.FileName.IndexOf("\\") + 1),
                                file.FileData);
                        }
                    }

                    AddLogMessage(
                        string.Concat("Результат сохранён в директорию: ", result.TaskGuid.ToString()),
                        LogMessageType.Info);
                }
                else
                {
                    labelHint.Text = "Задание на стадии расчёта.";
                }
            }
            catch
            {
            }
        }

        private void BrowseResultClick(object sender, EventArgs e)
        {
            var info = GetTaskInfoFromList(selectedActiveTask);

            if (Directory.Exists(info.Id.ToString()))
            {
                Process.Start("explorer.exe ", info.Id.ToString());
            }
        }

        private void RunApplicationClick(object sender, EventArgs e)
        {
            var applicationRunForm = new ApplicationRunForm(GetTaskInfoFromList(selectedActiveTask));
            applicationRunForm.ShowDialog();
        }

        private void DeleteResultClick(object sender, EventArgs e)
        {
            var info = GetTaskInfoFromList(selectedActiveTask);

            if (Directory.Exists(info.Id.ToString()))
            {
                Directory.Delete(info.Id.ToString(), true);

                AddLogMessage(
                        string.Format("Результат \"{0}\" удалён из директории {1}", info.Name, info.Id),
                        LogMessageType.Info);
            }
        }

        private void TaskMenuStripOpening(object sender, System.ComponentModel.CancelEventArgs e)
        {
            var info = GetTaskInfoFromList(selectedActiveTask);

            // Если задание выполнено его можно загрузить
            var isComplete = Convert.ToInt32(info.Progress) == 100;
            var isTaskResultDownloaded = Directory.Exists(info.Id.ToString());

            ShowAvailableContextMenuOperations(isComplete, isTaskResultDownloaded);
        }

        private void ResultsFolderClick(object sender, EventArgs e)
        {
            Process.Start("explorer.exe ", Directory.GetCurrentDirectory());
        }
    }
}